/*
 * NumberFormat.java
 * 
 * Copyright 2007 Tiberiumlabs
 *
 * This file is part of Tiberiumlabs Shards.
 *
 * Tiberiumlabs Shards is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Tiberiumlabs Shards is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.tiberiumlabs.shards.toolkit;

/**
 * class for parsing and formatting different numbers and sizes.
 * NumberFormat uses only primitive operations, with doubles, ints and longs,
 * so it uses much less RAM and CPU than DecimalFormat or other formatting facilities.
 *
 * @author <a href="mailto:paranoid.tiberiumlabs@gmail.com">Paranoid</a>
 */
public class NumberFormat {
    
    // <editor-fold defaultstate="collapsed" desc=" singleton implementation ">
    
    /**
     * NumberFormat is thread-safe, so it is better to use one instance for whole application.
     * @return instance of {@code NumberFormat}
     */
    public static final NumberFormat sharedInstance() {
        return INSTANCE;
    }
    private static final NumberFormat INSTANCE = new NumberFormat();

    private NumberFormat() {
    }
    
    // </editor-fold>
    
    /**
     * formattin byte size (file size as example) into String value,
     * with two digits after dot and actual measure (MB, GB or other).
     * @param size value to format
     * @return formatted size in bytes, kB, MB or other.
     */
    public String formatSize(long size) {
        return format(size, BYTES, 1024);
    }
    
    /**
     * formattin speed bytes (copy speed as example) into String value,
     * with two digits after dot and actual measure (MB/s, GB/s or other).
     * @param size value to format
     * @return formatted size in bytes/s, kB/s, MB/s or other.
     */
    public String formatSpeed(long size) {
        return format(size, BYTES_PER_SECOND, 1024);
    }
    
    /**
     * worker method to format any value without another string appending.
     * @param size value to format
     * @param measureUnits array of strings to use as measurement units. Use BYTES_PER_SECOND as example.
     * @param measureQuantity quantiry, required to step into next unit. Like 1024 for bytes, 1000 for meters or 100 for centiry.
     * @return formatted size with measure unit
     */
    public String format(long size, String[] measureUnits, int measureQuantity) {
        if (size <= 0) {
            return null;
        }
        
        // bytes:
        if (size < measureQuantity) {
            return size + measureUnits[0];
        }
        
        // incrementing "letter" while value >1023
        int i = 1;
        double d = size;
        while ((d = d / measureQuantity) > (measureQuantity-1) ) {
            i++;
        }

        // remove symbols after coma, left only 2:
        long l = (long) (d * 100);
        d = (double) l / 100;
        
        if (i < measureUnits.length) {
            return d + measureUnits[i];
        }
        
        // if we still here - value is tooo big for us.
        return String.valueOf(size);
    }
    
    /**
     * measurement units for size formatting, from bytes to yottabytes.
     */
    public static final String[] BYTES = {" B", " kB", " MB", " GB", " TB", " PB", " EB", " ZB", " YB"};
    /**
     * measurement units for speed formatting, from "bytes per second" to yottabytes.
     */
    public static final String[] BYTES_PER_SECOND = {" B/s"," kB/s"," MB/s"," GB/s"," TB/s"," PB/s"," EB/s"," ZB/s"," YB/s"};

}
